//! Copyright 2012 Xicut Technology, Inc.
//! All rights reserved
//!
#include "Config.h"
#include "BoardHardware.h"
#include "StrLib.h"
#include "UsartDriver.h"
#include "SIM900AppCommand.h"
#include "SIM900App.h"

#if defined (__FW_BUILD__)
extern "C"  {
#include "stm32f10x.h"
}
#endif


cSIM900App::eSIM900Process  cSIM900App::s_Process;
cSIM900App::eSIM900Process  cSIM900App::s_SubProcess;
cSysTick                    cSIM900App::s_ProcessTimeout;
cSIM900AppCommand*          cSIM900App::s_pSendPendingCmd;
cFIFO                       cSIM900App::s_SmsReceiveFreeFIFO;
U32                         cSIM900App::s_SmsReceiveFreeFIFO_Storage[cConfig::SIM900_RECEIVE_POOL_SIZE];


void cSIM900App::InitReset()
{
#if defined (__FW_BUILD__)
    GPIO_InitTypeDef GPIO_InitStructure;

    /* GPIOC Peripheral clock enable */
    RCC_APB2PeriphClockCmd(RESET_PERIPH, ENABLE);
    /* Configure PD0 and PD2 in output pushpull mode */
    GPIO_InitStructure.GPIO_Pin = RESET_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(RESET_PORT, &GPIO_InitStructure);
#endif

    SIM900_RESET;
    for (U32 cnt=0; cnt<100000; cnt++);
    SIM900_SET;
    for (U32 cnt=0; cnt<100000; cnt++);

    cUsartDriver::Init_Reset(19200);
    cSIM900AppCommand::Init_Reset();
    s_pSendPendingCmd = 0;
    s_SmsReceiveFreeFIFO.Init(s_SmsReceiveFreeFIFO_Storage, cConfig::SIM900_RECEIVE_POOL_SIZE);
    for (U32 i=0; i<cConfig::SIM900_RECEIVE_POOL_SIZE; ++i)
    {
        s_SmsReceiveFreeFIFO_Storage[i] = cSIM900AppCommand::Alloc()._;
    }

    s_Process = INIT_SIM900;
}


bool cSIM900App::IsProcessing()
{
    if (IDLE == s_Process) return (true);
    else return (false);
}


void cSIM900App::StartSendSms(SIM900AppCommandHandle smsHandle)
{
    s_pSendPendingCmd = cSIM900AppCommand::GetPointer(smsHandle);
    if ((3 <= s_pSendPendingCmd->m_Data.PhoneLen) && (13 >= s_pSendPendingCmd->m_Data.PhoneLen) && (cConfig::MAX_SMS_SUPPORT_LENGTH > s_pSendPendingCmd->m_Data.MsgLen))
    {
        U8 TempData[sizeof("AT+CMGS= +841993017973 \r\n")+5];
        cStrLib::Strcpy(TempData, (U8*)"AT+CMGS=\"", sizeof("AT+CMGS= ")-1);
        cStrLib::Strcpy(&TempData[sizeof("AT+CMGS= ")-1], s_pSendPendingCmd->m_Data.Phone, s_pSendPendingCmd->m_Data.PhoneLen);
        U8 iPhoneLen = s_pSendPendingCmd->m_Data.PhoneLen + sizeof("AT+CMGS= ")-1;
        TempData[iPhoneLen++] = '"';
        TempData[iPhoneLen++] = '\r';
        TempData[iPhoneLen++] = '\n';
        cUsartDriver::SendMsg(TempData, iPhoneLen);

        s_pSendPendingCmd->m_Data.Msg[s_pSendPendingCmd->m_Data.MsgLen++] = 0x1A;
        s_Process = SEND_ISSUE_PHONE_REQ;
    }
}


void cSIM900App::TaskProcess()
{
    U16 len;
    U8 *pData = cUsartDriver::GetIncomeMsg(len);
    switch (s_Process)
    {
    case IDLE:
        {
            if (0 != pData)
            {
                if (true == cStrLib::Strcmp(pData, (U8*)"RING", sizeof("RING")-1))
                {
                    // incoming call
                }
                else if (true == cStrLib::Strcmp(pData, (U8*)"NO CARRIER", sizeof("NO CARRIER")-1))
                {
                    // Call end
                }
                else if (true == cStrLib::Strcmp(pData, (U8*)"+CMTI:", sizeof("+CMTI:")-1))
                {
                    // incoming message
                }
            }
        } break;

    case INIT_SIM900:
        {
            if (true == cUsartDriver::SendMsg((U8*)"AT\r\n", (sizeof("AT\r\n")-1)))
            {
                ResetTimeout(200);
                s_Process = INIT_WAIT_OK_RPL;
                s_SubProcess = INIT_CONFIG_REQUEST;
            }
        } break;

    case INIT_CONFIG_REQUEST:
        {
            if (true == cUsartDriver::SendMsg((U8*)"AT+CMGF=1\r\n", (sizeof("AT+CMGF=1\r\n")-1)))
            {
                ResetTimeout(200);
                s_Process = INIT_WAIT_OK_RPL;
                s_SubProcess = INIT_SET_BAUDRATE_REQ;
            }
        } break;

    case INIT_SET_BAUDRATE_REQ:
        {
            if (true == cUsartDriver::SendMsg((U8*)"AT+IPR=19200\r\n", (sizeof("AT+IPR=19200\r\n")-1)))
            {
                ResetTimeout(200);
                s_Process = INIT_WAIT_OK_RPL;
                s_SubProcess = IDLE;
            }
        } break;

    case SEND_ISSUE_PHONE_REQ:
        {
            U8 tData[sizeof("AT+CMGS= +841993017973 \r\n")+5];
            cStrLib::Strcpy(tData, (U8*)"AT+CMGS=\"", sizeof("AT+CMGS= ")-1);
            cStrLib::Strcpy(&tData[sizeof("AT+CMGS= ")-1], s_pSendPendingCmd->m_Data.Phone, s_pSendPendingCmd->m_Data.PhoneLen);
            U8 iPhoneLen = s_pSendPendingCmd->m_Data.PhoneLen + sizeof("AT+CMGS= ")-1;
            tData[iPhoneLen++] = '"';
            tData[iPhoneLen++] = '\r';
            tData[iPhoneLen++] = '\n';
            if (true == cUsartDriver::SendMsg(tData, iPhoneLen))
            {
                s_Process = SEND_ISSUE_MSG_REQ;
            }
        } break;

    case SEND_ISSUE_PHONE_RPL:
        {
            if (0 != pData)
            {
                if (true == cStrLib::Strcmp(pData, (U8*)"> ", 2))
                {
                    s_pSendPendingCmd->m_Data.Msg[s_pSendPendingCmd->m_Data.MsgLen++] = 0x1A;

                    s_Process = SEND_ISSUE_MSG_REQ;
                }
            }
        } break;

    case SEND_ISSUE_MSG_REQ:
        {
            if (true == cUsartDriver::SendMsg(s_pSendPendingCmd->m_Data.Msg, s_pSendPendingCmd->m_Data.MsgLen))
            {
                ResetTimeout(8000);
                s_Process = INIT_WAIT_OK_RPL;
            }
        } break;

    case SEND_ISSUE_MSG_RPL:
        {
            if (0 != pData)
            {
                if (true == cStrLib::Strcmp(pData, (U8*)"OK", 2))
                {
                    s_Process = IDLE;
                    cSIM900AppCommand::s_SendStatusFIFO.Push(s_pSendPendingCmd->GetHandle()._);
                    s_pSendPendingCmd = 0;
                }
            }
        } break;

    case INIT_WAIT_OK_RPL:
        {
            if (0 != pData)
            {
                if (true == cStrLib::Strcmp(pData, (U8*)"OK", 2))
                {
                    s_Process = s_SubProcess;
                }
            }
        } break;

    default:
        {
            s_Process = IDLE;
        } break;
    }
}


void cSIM900App::RunOne()
{
    cUsartDriver::RunOne();

    TaskProcess();

    if (true == IsProcessing()) return;
    if (0 != s_pSendPendingCmd) return;

    SIM900AppCommandHandle sendHandle;
    if (false == cSIM900AppCommand::s_SendFIFO.Pop(sendHandle._)) return;
    StartSendSms(sendHandle);
}
